package com.dragons.dragonsvf.utils.secret;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

/**
 * @author Dragons.G
 * @date 2025-05-05 18:21:28
 * @description SM4国密加密
 */
public class SM4EncryptionUtil {

    public static void main(String[] args) throws Exception {
        String plainText = "@Gwl1314127";
        byte[] key = generateKey();
        System.out.println(key);
        byte[] fixedIV = "1234567890123456".getBytes(); // 固定IV示例

        // ECB模式测试
        String encryptedECB = encryptECB(plainText, key);
        String decryptedECB = decryptECB(encryptedECB, key);
        System.out.println("ECB模式解密结果: " + decryptedECB);

        // CBC模式测试
        String encryptedCBC = encryptCBC(plainText, key, fixedIV);
        String decryptedCBC = decryptCBC(encryptedCBC, key, fixedIV);
        System.out.println("CBC模式解密结果: " + decryptedCBC);
    }

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final String ALGORITHM_NAME = "SM4";
    private static final String DEFAULT_MODE = "SM4/ECB/PKCS5Padding"; // ECB模式确保相同输出
    private static final String CBC_MODE = "SM4/CBC/PKCS5Padding";
    private static final int KEY_SIZE = 128;

    /**
     * 生成随机密钥（16字节）
     */
    public static byte[] generateKey() throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, "BC");
        kg.init(KEY_SIZE, new SecureRandom());
        return kg.generateKey().getEncoded();
    }

    /**
     * 生成确定性密钥（基于种子）
     */
    public static byte[] generateKey(String seed) throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, "BC");
        kg.init(KEY_SIZE, new SecureRandom(seed.getBytes()));
        return kg.generateKey().getEncoded();
    }

    /**
     * ECB模式加密（无IV，相同输入输出固定）
     */
    public static String encryptECB(String plainText, byte[] key) throws Exception {
        validateKey(key);
        SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM_NAME);
        Cipher cipher = Cipher.getInstance(DEFAULT_MODE, "BC");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * CBC模式加密（需固定IV）
     */
    public static String encryptCBC(String plainText, byte[] key, byte[] iv) throws Exception {
        validateKeyAndIV(key, iv);
        SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM_NAME);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(CBC_MODE, "BC");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * ECB模式解密
     */
    public static String decryptECB(String encryptedText, byte[] key) throws Exception {
        validateKey(key);
        SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM_NAME);
        Cipher cipher = Cipher.getInstance(DEFAULT_MODE, "BC");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * CBC模式解密
     */
    public static String decryptCBC(String encryptedText, byte[] key, byte[] iv) throws Exception {
        validateKeyAndIV(key, iv);
        SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM_NAME);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(CBC_MODE, "BC");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    // 参数校验方法
    private static void validateKey(byte[] key) {
        if (key == null || key.length != 16) {
            throw new IllegalArgumentException("SM4密钥必须为16字节");
        }
    }

    private static void validateKeyAndIV(byte[] key, byte[] iv) {
        validateKey(key);
        if (iv == null || iv.length != 16) {
            throw new IllegalArgumentException("IV必须为16字节");
        }
    }


}
